package org.jumiz.db.util;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Field;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.jumiz.db.annotation.ColumnZ;
import org.jumiz.db.annotation.TableZ;
import org.jumiz.db.doc.bean.DocBeanZ;
import org.jumiz.db.result.TypeResultZ;

public final class DocDBUtilZ {
	
	private static String absPath = null;
	
	public static String packageName = "bean";
	
	public String doc(TypeResultZ type) throws ClassNotFoundException, IOException {
		if(TypeResultZ.JSON.equals(type)) {
			return json(packageName);
		}
		if(TypeResultZ.HTML.equals(type)) {
			return html(packageName);
		}
		return null;
	}
	
	private String html(String packageName) throws ClassNotFoundException, IOException {
		StringBuilder sb = new StringBuilder("<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title>JumiZ</title><style>table,td,th {border:1px solid #999;} th {background:#ccc;}</style></head><body>");
		List<DocBeanZ> list = doc(packageName);
		for(int i = 0, len = list.size(); i < len; i++) {
			DocBeanZ b = list.get(i);
			TableZ t = b.getTableZ();
			sb.append("<h2>").append(i + 1).append("、").append(t.nameC()).append("(").append(t.nameE()).append(")").append("</h2>")
			.append(t.desC()).append("<br>").append("<br>");
			;
			sb.append("<table cellspacing=\"0\" style='width:600px;'><tr><th>字段名</th><th>中文名</th><th>数据类型</th><th>是否为空</th><th style='max-width:25%;width:25%;'>备注</th></tr>");
			List<ColumnZ> fs = b.getColumnZs();
			for(ColumnZ f : fs) {
				sb.append("<tr>")
				.append("<td>").append(f.nameE()).append("</td>")
				.append("<td>").append(f.nameC()).append("</td>")
				.append("<td>").append(f.dataType()).append("</td>")
				.append("<td>").append(f.isNull()).append("</td>")
				.append("<td>").append(f.desC()).append("</td>")
				.append("</tr>");
			}
			sb.append("</table>");
		}
		sb.append("</body></html>");
		return sb.toString();
	}
	
	private String json(String packageName) throws ClassNotFoundException, IOException {
		List<DocBeanZ> list = doc(packageName);
		StringBuilder sb = new StringBuilder();
		for(DocBeanZ b : list) {
			TableZ t = b.getTableZ();
			sb.append("{\"nameE\":\"").append(t.nameE()).append("\",")
			.append("\"nameC\":\"").append(t.nameC()).append("\",")
			.append("\"desC\":\"").append(t.desC()).append("\",")
			.append("\"columnNames\":[")
			;
			List<ColumnZ> lis = b.getColumnZs();
			for(ColumnZ f : lis) {
				sb.append("{\"nameE\":\"").append(f.nameE()).append("\",")
				.append("\"nameC\":\"").append(f.nameC()).append("\",")
				.append("\"dataType\":\"").append(f.dataType()).append("\",")
				.append("\"isNull\":\"").append(f.isNull()).append("\",")
				.append("\"desC\":\"").append(f.desC()).append("\"},")
				;
			}
			if(sb.lastIndexOf(",") + 1 == sb.length()) {
				sb.deleteCharAt(sb.lastIndexOf(","));
			}
			sb.append("]},");
		}
		if(sb.lastIndexOf(",") > 0 && sb.lastIndexOf(",") + 1 == sb.length()) {
			sb.deleteCharAt(sb.lastIndexOf(","));
		}
		return sb.toString();
	}
	
	private List<DocBeanZ> doc(String pack) throws ClassNotFoundException, IOException {
		RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
		String[] path = runtime.getClassPath().split(";");
		List<DocBeanZ> list = new ArrayList<DocBeanZ>();
		for(int i = 0, len = path.length; i < len; i++) {
			List<DocBeanZ> dbs = doc(new File(path[i]), "bean");
			if(!dbs.isEmpty()) {
				list.addAll(dbs);
			}
		}
		return list;
	}
	
	private List<DocBeanZ> doc(File file, String pack) throws ClassNotFoundException, IOException {
		List<DocBeanZ> doclist = new ArrayList<DocBeanZ>();
		if(file.isDirectory()) {
			if(absPath == null) {
				absPath = file.getAbsolutePath();
			}
			String[] list = file.list();
			for(int i = 0, len = list.length; i < len; i++) {
				List<DocBeanZ> docs = doc(new File(file.getAbsoluteFile() + "/" + list[i]), pack);
				if(!docs.isEmpty()) {
					doclist.addAll(docs);
				}
			}
		} else if(file.getAbsolutePath().endsWith(".jar")) {
			URL url = new URL("jar:file:" + file.getAbsolutePath() + "!/META-INF/MANIFEST.MF");
			JarFile jarFile = ((JarURLConnection)url.openConnection()).getJarFile();
			Enumeration<JarEntry> ent = jarFile.entries();
			String filename;
			while(ent.hasMoreElements()) {
				filename = ent.nextElement().getName();
				filename = filename.replaceAll("/", ".");
				if(filename.startsWith(pack)) {
					DocBeanZ bean = getEntity(filename.substring(0, filename.length() - 6), pack);
					if(ent != null) {
						doclist.add(bean);
					}
				}
			}
		} else if(file.getAbsolutePath().endsWith(".class") && file.getAbsolutePath().startsWith(absPath)) {
			DocBeanZ ent = getEntity(file, pack);
			if(ent != null) {
				doclist.add(ent);
			}
		}
		return doclist;
	}
	
	private DocBeanZ getEntity(File file, String pack) throws ClassNotFoundException {
		String path = file.getAbsolutePath().replace(absPath, "").replaceAll("\\\\", ".").replaceAll("/", ".");
		if(path.startsWith(".")) {
			path = path.substring(1, path.length() - 6);
		} else {
			path = path.substring(0, path.length() - 6);
		}
		Class<?> c = Class.forName(path);
		if(!c.getPackage().getName().startsWith(pack)) {
			return null;
		}
		TableZ annotation = c.getAnnotation(TableZ.class);
		if(annotation == null) {
			return null;
		}
		List<ColumnZ> FiledZs = new ArrayList<ColumnZ>();
		Field[] fields = c.getDeclaredFields();
		for(Field f : fields) {
			ColumnZ an = f.getAnnotation(ColumnZ.class);
			if(an == null) {
				continue;
			}
			FiledZs.add(an);
		}
		DocBeanZ bean = new DocBeanZ(annotation, FiledZs);
		return bean;
	}
	
	private DocBeanZ getEntity(String filename, String pack) throws ClassNotFoundException {
		Class<?> c = Class.forName(filename);
		TableZ annotation = c.getAnnotation(TableZ.class);
		if(annotation == null) {
			return null;
		}
		List<ColumnZ> FiledZs = new ArrayList<ColumnZ>();
		Field[] fields = c.getDeclaredFields();
		for(Field f : fields) {
			ColumnZ an = f.getAnnotation(ColumnZ.class);
			if(an == null) {
				continue;
			}
			FiledZs.add(an);
		}
		DocBeanZ bean = new DocBeanZ(annotation, FiledZs);
		return bean;
	}

}
